﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

namespace isky.Plugin
{
    public static class EntityExtensions
    {
        /// <summary>
        /// 实体属性如果为空返回类型的默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="attributeLogicalName"></param>
        /// <returns></returns>
        public static T GetAttributeDefaultValue<T>(this Entity entity,
                                                 string attributeLogicalName)
        {
            return GetAttributeDefaultValue<T>(entity, attributeLogicalName, default(T));
        }

        /// <summary>
        /// 实体属性如果为空返回指定的默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="attributeLogicalName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetAttributeDefaultValue<T>(this Entity entity,
                                                 string attributeLogicalName,
                                                 T defaultValue)
        {
            return entity.Contains(attributeLogicalName)
                ? entity.GetAttributeValue<T>(attributeLogicalName)
                    : defaultValue;
        }

        public static object checkEntityAttr(this Entity entity, string attrName)
        {
            return entity.Attributes.Contains(attrName) ? entity[attrName] : null;
        }

        public static T GetAttributeInputOrImage<T>(Entity preEntity, Entity PreImageEntity, string attrName, T defaultValue)
        {
            if (preEntity.Attributes.ContainsKey(attrName))
            {
                return preEntity.GetAttributeDefaultValue<T>(attrName, defaultValue);
            }
            else
            {
                return PreImageEntity.GetAttributeDefaultValue<T>(attrName, defaultValue);
            }
        }


        /// <summary>
        /// 根据单据Id获取关系表中的Id集合
        /// </summary>
        /// <param name="service">service</param>
        /// <param name="documentId">单据Id</param>
        /// <param name="tableName">关系表名称</param>
        /// <param name="documentIdName">单据Id名称</param>
        /// /// <param name="setName">查询的列名</param>
        /// <returns></returns>
        public static EntityCollection GetTableDataIdById(IOrganizationService service, string documentId, string tableName, string documentIdName,string setName)
        {
            EntityCollection result = null;
            var query = CrmQuery.Select(new ColumnSet(setName))
                          .From(tableName)
                          .Where(tableName, documentIdName, ConditionOperator.Equal, new object[] { documentId }).Query;
            result = service.RetrieveMultiple(query);
            if (result != null
                && result.Entities != null
                && result.Entities.Count > 0)
            {
                return result;
            }
            return null;
        }


        #region 克隆
        public static Entity Clone(this Entity entity, bool includeRelatedEntities = false)
        {
            Entity entity2 = Activator.CreateInstance(entity.GetType()) as Entity;
            List<Tuple<Entity, Entity>> path = new List<Tuple<Entity, Entity>> {
        new Tuple<Entity, Entity>(entity, entity2)
        };
            return Clone(entity, entity2, includeRelatedEntities, path);
        }

        private static Entity Clone(Entity entity, Entity clone, bool includeRelatedEntities, IEnumerable<Tuple<Entity, Entity>> path)
        {
            clone.LogicalName = entity.LogicalName;
            clone.Id = entity.Id;
            clone.EntityState = entity.EntityState;
            foreach (KeyValuePair<string, string> pair in entity.FormattedValues)
            {
                clone.FormattedValues[pair.Key] = pair.Value;
            }
            foreach (KeyValuePair<string, object> pair2 in entity.Attributes)
            {
                object obj2 = CloneAttribute(pair2.Value, includeRelatedEntities);
                clone.Attributes[pair2.Key] = obj2;
            }
            if (includeRelatedEntities)
            {
                foreach (KeyValuePair<Relationship, EntityCollection> pair3 in entity.RelatedEntities)
                {
                    EntityCollection entitys = CloneEntityCollection(pair3.Value, true, path);
                    clone.RelatedEntities[pair3.Key] = entitys;
                }
            }
            return clone;
        }

        private static object CloneAttribute(object attribute, bool includeRelatedEntities)
        {
            EntityReference reference = attribute as EntityReference;
            if (reference != null)
            {
                return new EntityReference(reference.LogicalName, reference.Id) { Name = reference.Name };
            }
            OptionSetValue value2 = attribute as OptionSetValue;
            if (value2 != null)
            {
                return new OptionSetValue(value2.Value);
            }
            Money money = attribute as Money;
            if (money != null)
            {
                return new Money(money.Value);
            }
            EntityCollection entities = attribute as EntityCollection;
            if (entities != null)
            {
                return CloneEntityCollection(entities, includeRelatedEntities, new List<Tuple<Entity, Entity>>());
            }
            return attribute;
        }

        private static EntityCollection CloneEntityCollection(EntityCollection entities, bool includeRelatedEntities, IEnumerable<Tuple<Entity, Entity>> path)
        {
            EntityCollection entitys = new EntityCollection
            {
                EntityName = entities.EntityName,
                MinActiveRowVersion = entities.MinActiveRowVersion,
                MoreRecords = entities.MoreRecords,
                PagingCookie = entities.PagingCookie,
                TotalRecordCount = entities.TotalRecordCount,
                TotalRecordCountLimitExceeded = entities.TotalRecordCountLimitExceeded
            };
            foreach (Entity entity in entities.Entities)
            {
                Entity e = entity;
                Tuple<Entity, Entity> tuple = path.FirstOrDefault<Tuple<Entity, Entity>>(p => p.Item1 == e);
                if (tuple != null)
                {
                    entitys.Entities.Add(tuple.Item2);
                }
                else
                {
                    Entity entity2 = Activator.CreateInstance(entity.GetType()) as Entity;
                    List<Tuple<Entity, Entity>> second = new List<Tuple<Entity, Entity>> {
                new Tuple<Entity, Entity>(entity, entity2)
            };
                    Entity item = Clone(entity, entity2, includeRelatedEntities, path.Concat<Tuple<Entity, Entity>>(second));
                    entitys.Entities.Add(item);
                }
            }
            return entitys;
        }
        #endregion

        /// <summary>
        ///  拆分List
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">List源</param>
        /// <param name="chunkSize">List大小</param>
        /// <returns></returns>
        public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize)
        {
            return source
                .Select((x, i) => new { Index = i, Value = x })
                .GroupBy(x => x.Index / chunkSize)
                .Select(x => x.Select(v => v.Value).ToList())
                .ToList();
        }
    }
}
